#pragma once
#include "util.hpp"
#include<unordered_map>
#include<string>
#include<list>
#include "lighttcp/sslserver.hpp"
class HTTPSServer:public SSLServer{
	public:
	//请求头限制 MAXKEYNUM针对字段
	static const unsigned int LENVERSION=8,LENMETHODKEY=8,LENTABLEKEY=32,
	LENTABLEVALUE=148,LENRESOURCEKEY=LENTABLEVALUE,MAXKEYNUM=16;
	typedef SSLServer::ThreadInfo ThreadInfo;
	struct Request;
	typedef bool(*MethodCallback)(HTTPSServer*,ThreadInfo*,Request*);
	typedef void(*RequestLostCallback)(HTTPSServer*,ThreadInfo*,Request*,void*);
	typedef void(*DataCallback)(HTTPSServer*,ThreadInfo*,Request*);
	static void emptyrequestlost(HTTPSServer*,ThreadInfo*,Request*,void*);
	typedef struct{
		MethodCallback callback;
		bool skipvalue;
	}MethodPair;
	private:
	typedef std::unordered_map<std::string,MethodPair> MethodTable;
	public:
	static const StringTable defaulttable;
	struct Request{
		friend class HTTPSServer;
		enum ins_type{
			ins_method=0,ins_preurl,ins_url,ins_urlhex1,ins_urlhex2,
			ins_querykey,ins_querykeyhex1,ins_querykeyhex2,ins_queryvalue,
			ins_queryvaluehex1,ins_queryvaluehex2,ins_version,
			ins_versionend,ins_key,ins_keyhex1,ins_keyhex2,ins_value,
			ins_valuehex1,ins_valuehex2,ins_valueend,ins_requestend,
			ins_skip,ins_skipend,ins_skip2
		};
		MethodPair* method;//由server设置和检查
		unsigned int headcount;
		char keybuffer[LENTABLEKEY],valuebuffer[LENTABLEVALUE];//最大长度-1
		char got,hex;
		Memory memory;//默认为{nullptr,0,true} getdata回调时设为读取数据
		unsigned int mode;//当前处理模式
		unsigned int versionlength;
		std::list<char*> responsebuffer;//先进先出
		DataInfo* info;
		public:
		char version[LENVERSION];//使用memcmp比较
		StringTable value;//包含url参数
		Resource* url;//由server设置
		~Request();
		//memory不重置
		void reset();
		void print();
		//需要手动管理原指针的生命周期
		void setdata(void* data,size_t size,bool autofree);
		size_t datasize();
		size_t versionsize();
		bool keep();
	};
	~HTTPSServer()override;
	private:
	MethodTable methods;
	std::unordered_map<DataInfo*,Request*>* requests;
	Dir* root;//静态资源 启动时加载 随服务器实例一起析构
	RequestLostCallback requestlost;
	static bool onmethod(HTTPSServer*,ThreadInfo*,DataInfo*,void*);
	//url不允许有空格
	static bool onhead(HTTPSServer*,ThreadInfo*,DataInfo*,Request*);
	static bool onfinishdata(HTTPSServer*,ThreadInfo*,DataInfo*,Request*);
	static bool ondatacloseclient(SSLServer*,ThreadInfo*,DataInfo*,void*);
	static void oncloseclient(HTTPSServer*,ThreadInfo*,DataInfo*,void*);
	
	public:
	static void emptysendback(HTTPSServer*,ThreadInfo*,Request*);
	/*
	rootpath为静态资源根目录 compressmethod可选为""|gzip|zlib|deflate
	method返回true则继续接收下一个http请求 请求头解析结束时char*==memory.data
	默认处理400-非法请求 401-非法查询字符串 402-字段超限 404-找不到url资源
	*/
	HTTPSServer(const char* rootpath,const std::string& compressmethod,
	std::initializer_list<std::pair<std::string,MethodPair>> methods);
	//调用需要方法返回false 否则无法生效
	void getdata(ThreadInfo* from,DataInfo* info,Request* request,
	void* buffer,size_t size,bool autofree,MethodCallback callback);
	//keep==false则响应结束就断开连接 内存不足抛std::bad_alloc
	void response(ThreadInfo* from,Request* request,unsigned int statuscode,
	const std::string& statustext,const StringTable& value,void* data,size_t size,
	bool keep,DataCallback callback=emptysendback);
	//返回size大小的可写内存 用于需要加工的临时内存（如返回的查询结果） 内容同响应头一起发送
	char* response(ThreadInfo* from,Request* request,unsigned int statuscode,
	const std::string& statustext,const StringTable& value,size_t size,bool keep,
	DataCallback callback=emptysendback);
	/*封装response 仅支持部分常用格式(文本编码utf8) 不支持则不响应并返回false
	会自动添加type&length&encoding=deflate字段
	*/
	bool sendfile(ThreadInfo* from,Request* request,StringTable& value,File* file,bool keep);
	bool sendfile(ThreadInfo* from,Request* request,File* file,bool keep);
	int run(const char* keypath,const char* certpath,const char* address,unsigned int _port,RequestLostCallback onlost=emptyrequestlost,
	void* lostarg=nullptr,unsigned int nthread=2,unsigned int maxpending=50,
	time_t timeout=120,size_t maxconnect=1000);
	//由接收连接的主线程调用 可用于数据库读写硬盘场景
	virtual void update()override;
	static bool openlib();
	static void closelib();
};